package com.jfinal.mvc;

import java.io.IOException;

import javax.servlet.FilterConfig;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.jfinal.config.Smart4jConfig;

/**
 * 前端控制器
 */
public class Smart4jFilter implements Filter {
	private static final Logger logger = LoggerFactory.getLogger(Smart4jFilter.class);

	private ActionHandler handler;
	private String encoding;
	private int contextPathLength;

	@Override
	public void init(FilterConfig servletConfig) throws ServletException {
		Smart4jConfig jfinalConfig = createJFinalConfig(servletConfig.getInitParameter("configClass"));

		if (!Smart4j.me().init(jfinalConfig, servletConfig.getServletContext()))
			throw new RuntimeException("JFinal init error!");

		handler = Smart4j.me().getActionHandler();
		encoding = Smart4j.me().getConstants().getEncoding();

		String contextPath = servletConfig.getServletContext().getContextPath();
		contextPathLength = (contextPath == null || "/".equals(contextPath) ? 0 : contextPath.length());
	}

	private Smart4jConfig createJFinalConfig(String configClass) {
		if (configClass == null)
			throw new RuntimeException("Please set configClass parameter of JFinalFilter in web.xml");

		Object temp;
		try {
			temp = Class.forName(configClass).newInstance();
		} catch (Exception e) {
			throw new RuntimeException("Can not create instance of class: " + configClass, e);
		}

		if (temp instanceof Smart4jConfig)
			return (Smart4jConfig) temp;
		else
			throw new RuntimeException(
					"Can not create instance of class: " + configClass + ". Please check the config in web.xml");
	}

	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		request.setCharacterEncoding(encoding);
		HttpServletRequest req = (HttpServletRequest) request;
		HttpServletResponse resp = (HttpServletResponse) response;

		String target = req.getRequestURI();
		if (contextPathLength != 0)
			target = target.substring(contextPathLength);

		if (target.indexOf('.') != -1) {
			chain.doFilter(request, response);
			return;
		}
		
		try {
			handler.handle(target, req, resp);
		} catch (Exception e) {
			if (logger.isErrorEnabled()) {
				String qs = req.getQueryString();
				logger.error(qs == null ? target : target + "?" + qs, e);
			}
		}
	}

	@Override
	public void destroy() {
		Smart4j.me().stopPlugins();
	}
}
